package com.dfch.auto.appium.script;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dfch.auto.appium.ui.TipWindow;
import com.dfch.auto.appium.utils.ADBUtil;
import com.dfch.auto.appium.utils.AndroidCMDUtil;
import com.dfch.auto.appium.utils.AppiumUtils;
import com.dfch.auto.appium.utils.RequestUtil;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.AndroidElement;
import io.appium.java_client.remote.AndroidMobileCapabilityType;
import io.appium.java_client.remote.AutomationName;
import io.appium.java_client.remote.MobileCapabilityType;
import org.openqa.selenium.Platform;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.URL;
import java.util.List;
import java.util.concurrent.CountDownLatch;

public class AutoScript {


    private static final Logger LOGGER = LoggerFactory.getLogger(AutoScript.class);

    private static String[] PARAM_KEYS = {"platform_version", "device_name", "package", "activity", "url"};

    //{"platform_version":"4.4","device_name":"127.0.0.1:21503","url":"http://127.0.0.1:6000/wd/hub","keys":"很不错"}
    public static void main(String[] args) throws Exception {
        try {
//            PropertyConfigurator.configure("D://workspace/ms/client/appium/src/main/resources/log4j.properties");

            String scriptId = args[0];
//
            //            String scriptId = "089c3a1e3f3542338b2c6200fc67e7eb";
            if (StringUtils.isEmpty(scriptId)) {
                LOGGER.error("没有指定要执行的脚本");
                return;
            }
            ADBUtil.hasEnv("ANDROID_HOME", "%ANDROID_HOME%\\platform-tools", "%ANDROID_HOME%\\tools");

            List<String> devices = ADBUtil.getDevices();


            if (CollectionUtils.isEmpty(devices)) {
                throw new RuntimeException("没有发现任何设备或虚拟机，如果已经连接设备/虚拟机，请尝试重启或拔掉USB线重新连接并检查USB调试选项!");
            }


            new Thread(new Runnable() {
                @Override
                public void run() {

                    try {
                        AppiumUtils.destoryAll(devices, 6000);

                        AppiumUtils.createAppiumServers(devices, 6000);
                        LOGGER.debug("脚本启动参数:{}", JSON.toJSONString(args));
                    } catch (IOException e) {
                        LOGGER.error("创建appium服务器失败:", e);
                    }

                }
            }).start();

            Thread.sleep(3000);


            String response = RequestUtil.send("http://47.100.41.110:18000/as/get?sid=" + scriptId, null, "utf-8");

            LOGGER.debug("获取脚本结果:{}", response);

            JSONObject paramMap = JSON.parseObject(response);
            if (!paramMap.get("result").equals("0")) {
                throw new RuntimeException("获取脚本失败:" + paramMap.get("msg"));
            }


            JSONObject scriptObject = (JSONObject) paramMap.get("data");
            LOGGER.info("正在执行脚本:{}", scriptObject.get("name"));

            for (String key : PARAM_KEYS) {
                if (key.equals("device_name")) {
                    continue;
                }
                if (scriptObject.containsKey(key) == false) {
                    throw new RuntimeException("脚本缺少基础配置项:" + key);
                }
            }


            CountDownLatch cdl = new CountDownLatch(devices.size());
            AndroidCMDUtil util = new AndroidCMDUtil();
            int startPort = 6000;
            for (final String device : devices) {
                startPort++;
                final Integer tempPort = startPort;
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Integer loop = (Integer) scriptObject.get("loop");
                        loop = loop == null ? 1 : loop;
                        Integer step = 0;
                        Long now = System.currentTimeMillis();

                        try {
                            AndroidDriver<AndroidElement> driver = initDriver(scriptObject.get(PARAM_KEYS[0]).toString(), device, scriptObject.get(PARAM_KEYS[2]).toString(), scriptObject.get(PARAM_KEYS[3]).toString(), "http://127.0.0.1:" + tempPort + "/wd/hub");
                            JSONArray steps = (JSONArray) scriptObject.get("steps");


                            while (step < loop) {
                                for (Object stepCMD : steps) {
                                    Long snow = System.currentTimeMillis();
                                    try {
                                        JSONObject actionObject = (JSONObject) stepCMD;
                                        String action = (String) actionObject.get("action");
                                        String selector = (String) actionObject.get("selector");
                                        JSONArray targets = (JSONArray) actionObject.get("targets");
                                        JSONArray params = (JSONArray) actionObject.get("params");
                                        util.execute(driver, action, selector, targets, params);
                                    } catch (Exception ex) {
                                        LOGGER.error("执行脚本流程中发生错误,跳过此次操作!");
                                    }
                                    LOGGER.info("执行一次 脚本结束,耗时:{}s", new BigDecimal(snow / 1000).doubleValue());
                                }
                                step++;
                            }
//                            new TouchAction(driver).release();
                        } catch (Exception ex) {
                            LOGGER.info("脚本执行发生错误", ex);
                        } finally {
                            cdl.countDown();
                        }
                        LOGGER.info("脚本执行再设备{}上执行{}次,总耗时:{}ms", scriptObject.get(PARAM_KEYS[1]).toString(), loop, System.currentTimeMillis() - now);
                    }
                }).start();
            }

            cdl.await();
            LOGGER.info("脚本执行结束，正在回收进程");
            AppiumUtils.destoryAll(devices, 6000);
        } catch (Exception ex) {
            LOGGER.error("脚本执行发生错误", ex);
            new TipWindow("脚本执行发生错误", ex.getMessage());
        }

    }

    private static AndroidDriver initDriver(String PLATFORM_VERSION, String DEVICE_NAME, String APP_PACKAGE, String APP_ACTIVITY, String APPIUM_SERVER) throws Exception {
        //System.out.println("Hello world!");
        DesiredCapabilities capabilities = new DesiredCapabilities();
        // Platform
        capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, Platform.ANDROID);
        // Android system version
        //capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.0");
        capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, PLATFORM_VERSION);
        // Adb device name
        // capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "36a98632");
        capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, DEVICE_NAME);
        // Reset app and clear cache
        capabilities.setCapability(MobileCapabilityType.NO_RESET, true);
        // Application package name
        capabilities.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, APP_PACKAGE);
        // Application activity name
        capabilities.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, APP_ACTIVITY);
        // Unicode keyboard
        capabilities.setCapability(AndroidMobileCapabilityType.UNICODE_KEYBOARD, true);
        // Hide keyboard
        capabilities.setCapability(AndroidMobileCapabilityType.RESET_KEYBOARD, true);
        // Set automation type
        capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.APPIUM);

        AndroidDriver<AndroidElement> driver = new AndroidDriver<>(new URL(APPIUM_SERVER), capabilities);
        //启动后等待视频加载

        Thread.sleep(3000);

        return driver;
    }


}
